package com.greenyoung.pwiki.oss.controller;

import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.greenyoung.pwiki.oss.cloud.CloudStorageConfig;
import com.greenyoung.pwiki.oss.cloud.OSSFactory;
import com.greenyoung.pwiki.oss.consts.ConstConfig;
import com.greenyoung.pwiki.oss.consts.ConstMq;
import com.greenyoung.pwiki.oss.entity.ElIndexRecordEntity;
import com.greenyoung.pwiki.oss.entity.OssFileEntity;
import com.greenyoung.pwiki.oss.entity.Result;
import com.greenyoung.pwiki.oss.entity.UserEntity;
import com.greenyoung.pwiki.oss.exception.MyException;
import com.greenyoung.pwiki.oss.service.ConfigService;
import com.greenyoung.pwiki.oss.service.ElIndexRecordService;
import com.greenyoung.pwiki.oss.service.OssFileService;
import com.greenyoung.pwiki.oss.utils.GlobalIdUtil;
import com.greenyoung.pwiki.oss.utils.PageUtils;
import com.greenyoung.pwiki.oss.validator.ValidatorUtils;
import com.greenyoung.pwiki.oss.validator.group.AliyunGroup;
import com.greenyoung.pwiki.oss.validator.group.QcloudGroup;
import com.greenyoung.pwiki.oss.validator.group.QiniuGroup;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.Date;
import java.util.Map;

@RestController
@RequestMapping("/oss")
@Api(tags = "oss文件上传及配置搜索")
public class OssController {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private ConfigService configService;
    @Autowired
    private OssFileService ossFileService;
    @Autowired
    private ElIndexRecordService elIndexRecordService;
    @Autowired
    private AmqpTemplate rabbitTemplate;

    @GetMapping("/config")
    @PreAuthorize("hasAuthority('oss:config:get')")
    @ApiOperation(value = "获取云存储配置信息")
    public Result config() {
        CloudStorageConfig config = configService.getConfigObject(ConstConfig.CLOUD_STORAGE_CONFIG_KEY, CloudStorageConfig.class);

        return Result.ok().put("config", config);
    }

    /**
     * 保存云存储配置信息，保存前进行数据校验
     * 校验规则已添加，校验失败后会通过全局异常处理器返回错误信息
     *
     * @see com.greenyoung.pwiki.oss.cloud.CloudStorageConfig
     */
    @PostMapping("/config")
    @PreAuthorize("hasAuthority('oss:config:post')")
    @ApiOperation(value = "保存云存储配置信息")
//    @RequiresPermissions("sys:oss:all")
    public Result saveConfig(@RequestBody CloudStorageConfig config) {
        //校验类型
        ValidatorUtils.validateEntity(config);

        switch (config.getType()) {
            case 1:
                //校验七牛数据
                ValidatorUtils.validateEntity(config, QiniuGroup.class);
                break;
            case 2:
                //校验阿里云数据
                ValidatorUtils.validateEntity(config, AliyunGroup.class);
                break;
            case 3:
                //校验腾讯云数据
                ValidatorUtils.validateEntity(config, QcloudGroup.class);
                break;
            default:
                break;
        }
        configService.updateValueByKey(ConstConfig.CLOUD_STORAGE_CONFIG_KEY, new Gson().toJson(config));

        return Result.ok();
    }

    /**
     * 文件列表
     */
    @GetMapping("/file")
    @PreAuthorize("hasAuthority('oss:file:get')")
    @ApiOperation(value = "获取用户文件列表")
    public Result list(@RequestParam Map<String, Object> queryParams) {
        UserEntity userEntity = (UserEntity) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        PageUtils page = ossFileService.queryPageByUserId(queryParams, userEntity.getId());
        return Result.ok().put("page", page);
    }

    /**
     * 上传文件,文件名通过UUID生成
     * 文件上传后发送消息到elastic search索引消息队列
     *
     * @see com.greenyoung.pwiki.oss.cloud.AbsCloudStorageService#getPath(String prefix, String suffix)
     */
    @PostMapping("/file")
    @PreAuthorize("hasAuthority('oss:file:post') and hasAuthority('el:index')")
    public Result upload(@RequestParam("file") MultipartFile file) throws Exception {
        if (file.isEmpty()) {
            throw new MyException("上传文件不能为空");
        }

        //上传文件到云端，suffix文件后缀中包含点
        String fileName = file.getOriginalFilename();
        String suffix = fileName.substring(file.getOriginalFilename().lastIndexOf("."));
        //实际的上传行为，通过工厂获取到具体的云服务，进行上传，返回一个上传后的文件地址
        String url = OSSFactory.build().uploadSuffix(file.getBytes(), suffix);

        //保存文件信息
        OssFileEntity ossFileEntity = new OssFileEntity();
        Long fileId = GlobalIdUtil.nextId();
        ossFileEntity.setId(fileId);
        ossFileEntity.setName(fileName);
        ossFileEntity.setUrl(url);
        // TODO: 对文件类型进行校验
        String fileType = suffix.replace(".", "");
        ossFileEntity.setType(fileType);
        ossFileEntity.setCreateTime(new Date());

        ossFileService.save(ossFileEntity);

        //如果是pdf或者md文件，则发送到消息队列进行索引
        switch (fileType) {
            case "pdf":
            case "md":
                ElIndexRecordEntity elIndexRecordEntity = new ElIndexRecordEntity();
                elIndexRecordEntity.setId(ossFileEntity.getId());
                elIndexRecordEntity.setStatus(0);
                elIndexRecordEntity.setName(ossFileEntity.getName());
                elIndexRecordEntity.setType(ossFileEntity.getType());
                elIndexRecordEntity.setUrl(ossFileEntity.getUrl());
                Date date = new Date();
                elIndexRecordEntity.setCreateTime(date);
                elIndexRecordEntity.setUpdateTime(date);
                elIndexRecordService.save(elIndexRecordEntity);
                logger.info("[+] 索引记录已存储：" + elIndexRecordEntity);

                String msg = JSON.toJSONString(ossFileEntity);
                this.rabbitTemplate.convertAndSend(ConstMq.ELASTICSEARCH_INDEX_QUEUE, msg);
                logger.info("[+] 向消息队列发送消息:" + msg);
                break;
            default:
                break;
        }

        return Result.ok().put("url", url);
    }
}
